home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1994 / MacHack 1994.toast / MacHack™ 1987-1994 / MacHack™ '92 / Hacks ’92 / ARAStatus ƒ / ARAStatus.c next >
Encoding:
C/C++ Source or Header  |  1992-06-20  |  13.0 KB  |  555 lines  |  [TEXT/KAHL]

  1. /*
  2.     ARAStatus.c
  3.     
  4.     Extension to show the connection status of ARA. Will add a system menu to control
  5.     various functions of ARA. Also, show the connect time.
  6.     
  7.     by Patrick Beard & Chris Allen.
  8.     
  9.     © 1992 Gene Scott Software.
  10. */
  11.  
  12. #include <string.h>
  13. #include <Traps.h>
  14. #include <stdarg.h>
  15. #include <stdio.h>
  16. #include <stddef.h>
  17.  
  18. #ifndef __MENUS__
  19. #include <Menus.h>
  20. #endif
  21. #ifndef __GESTALTEQU__
  22. #include <GestaltEqu.h>
  23. #endif
  24. #ifndef __REMOTEACCESSINTERFACE__
  25. #include <RemoteAccessInterface.h>
  26. #endif
  27. #ifndef __NOTIFICATION__
  28. #include <Notification.h>
  29. #endif
  30.  
  31. #include "Exceptions.h"
  32. #include "Extension.h"
  33. #include "GenericPatch.h"
  34. #include "IconSuite.h"
  35. #include "MenusList.h"
  36. #include "ShowIconFamily.h"
  37.  
  38.  
  39. static int dprintf(const char* format, ...);
  40.  
  41. #if __option(a4_globals)
  42. #define cBaseSystemMenuId -16488
  43. #else
  44. #define cBaseSystemMenuId 5000
  45. #endif
  46.  
  47. enum {
  48.     eAboutARAStatus = 1,
  49.     eDisconnect,
  50.     eShowTimeConnected
  51. };
  52.  
  53. enum {
  54.     eNotConnectedIcon = 0,
  55.     eConnectedIcon,
  56.     eTransitionIcon
  57. };
  58.  
  59. #define cAboutStrings 128
  60.  
  61. struct IconString {
  62.     char itsLength;                // always 5.
  63.     char itsFlag;                // always 1.
  64.     Handle itsSuite;            // handle to an icon suite.
  65. };
  66.  
  67. typedef struct IconString IconString;
  68.  
  69. //
  70. // globals.
  71. //
  72.  
  73. #pragma mark globals
  74.  
  75. IconString theIconStrings[3];
  76. MenuHandle theARAStatusMenu;
  77. MenuHandle theTimeConnectedMenu;
  78. long theLastTimeConnected = 0;
  79. Boolean theShowTimeConnected = true;
  80. Boolean theConnectionState = false;
  81. Boolean theMenuBarDirty = false;
  82. unsigned char theEmptyStr[1] = { '\0' };
  83. Str255 theAboutMessage;
  84.  
  85. //
  86. // ARA functions.
  87. //
  88.  
  89. static void ARADisconnect()
  90. {
  91.     TRemoteAccessParamBlock pb;
  92.  
  93.     // set up the Remote Access PB
  94.     pb.DISCONNECT.csCode = RAM_EXTENDED_CALL;        // extended call
  95.     pb.DISCONNECT.resultStrPtr = nil;                // don’t want result strings
  96.     pb.DISCONNECT.extendedType = (Ptr)REMOTEACCESSNAME;    // to Remote Access
  97.     pb.DISCONNECT.extendedCode = CmdRemoteAccess_Disconnect;  // disconnect command
  98.     pb.DISCONNECT.portGlobalsPtr = nil;                // user port
  99.     pb.DISCONNECT.abortOnlyThisPB = nil;            // don't get tied to any specific pb
  100.     pb.DISCONNECT.optionFlags = 0| kNSShowStatus;        // show status while disconnecting
  101.     PBRemoteAccess(&pb, false);        // issue sync call
  102. }
  103.  
  104. static TRemoteAccessStatusParam* ARAStatus()
  105. {
  106.     static TRemoteAccessParamBlock thePB;
  107.     register TRemoteAccessParamBlock* pb = &thePB;
  108.     static long sequence = 0;
  109.     
  110.     // set up the Status PB
  111.     pb->STATUS.csCode = RAM_EXTENDED_CALL;                    // extended call
  112.     pb->STATUS.resultStrPtr = nil;                            // put results here
  113.     pb->STATUS.portGlobalsPtr = nil;                        // do UserPort
  114.     pb->STATUS.extendedType = (Ptr)REMOTEACCESSNAME;        // to Netshare
  115.     pb->STATUS.extendedCode = CmdRemoteAccess_Status;        // status command
  116.     pb->STATUS.userNamePtr = nil;
  117.     pb->STATUS.connectedToNamePtr = nil;
  118.     pb->STATUS.theLastStatusMsgPtr = nil;
  119.     pb->STATUS.statusUserNamePtr = nil;
  120.     pb->STATUS.statusMsgSeqNum = sequence++;            // set seqnum
  121.  
  122.     PBRemoteAccess(pb, false);
  123.     
  124.     return &pb->STATUS;
  125. }
  126.  
  127. //
  128. // Nasty menu manipulation functions.
  129. //
  130.  
  131. #pragma mark menu_functions
  132.  
  133. static short StrWidth(StringPtr str)
  134. {
  135.     GrafPtr* portPtr = *(GrafPtr**)GetA5();
  136.     GrafPtr oldPort;
  137.     short width;
  138.     
  139.     oldPort = *portPtr, *portPtr = WMgrPort;
  140.     width = StringWidth(str);
  141.     *portPtr = oldPort;
  142.     
  143.     return width;
  144. }
  145.  
  146. static Boolean IdInMenuList(MenusListHandle menuList, short id)
  147. {
  148.     MenusList* menus = *menuList;
  149.     short i, menuCount = menus->itemsOffset / sizeof(MenuElement);
  150.     
  151.     for (i = 0; i < menuCount; ++i) {
  152.         MenuHandle m = menus->elements[i].menu;
  153.         if ((**m).menuID == id) return true;
  154.     }
  155.     return false;
  156. }
  157.  
  158. static void DirectInsertMenu(MenusListHandle menuList, MenuHandle menu, MenuHandle before)
  159. {
  160.     short id = cBaseSystemMenuId;
  161.     MenuHandle leftMenu = nil;
  162.     MenusList* menus;
  163.     short i, menuCount;
  164.     MenuElement newElement;
  165.     long offset;
  166.     short width;
  167.     
  168.     HLock(menuList);
  169.     menus = *menuList;
  170.     menuCount = menus->itemsOffset / sizeof(MenuElement);
  171.     
  172.     // compute width of the menu title.
  173.     HLock(menu);
  174.     width = 8 + StrWidth((**menu).menuData);
  175.     HUnlock(menu);
  176.     
  177.     // generate a unique id.
  178.     while (IdInMenuList(menuList, id)) ++id;
  179.     
  180.     (**menu).menuID = id;
  181.     newElement.menu = menu;
  182.     if (!before) {
  183.         newElement.leftEdge = menus->rightEdge;
  184.         menus->rightEdge = newElement.leftEdge + width;
  185.         offset = sizeof(MenusList) + menus->itemsOffset; // menuCount * sizeof(MenuElement)
  186.     } else {
  187.         MenuElement* elements = menus->elements;
  188.         for (i = 0; i < menuCount; ++i, ++elements) {
  189.             if (elements->menu == before) {
  190.                 offset = sizeof(MenusList) + i * sizeof(MenuElement);
  191.                 newElement.leftEdge = elements->leftEdge - width - 4;
  192.                 break;
  193.             }
  194.         }
  195.     }
  196.     menus->itemsOffset += 6;
  197.     HUnlock(menuList);
  198.     Munger(menuList, offset, nil, 0, (Ptr)&newElement, sizeof(MenuElement));
  199. }
  200.  
  201. static void DirectRemoveMenu(MenusListHandle menuList, MenuHandle menu)
  202. {
  203.     MenusList* menus = *menuList;
  204.     short i, menuCount = menus->itemsOffset / sizeof(MenuElement);
  205.     
  206.     // remove the menu from the list.
  207.     for (i = 0; i < menuCount; ++i) {
  208.         if (menus->elements[i].menu == menu) {
  209.             MenuElement element;
  210.             long offset = sizeof(MenusList) + i * sizeof(MenuElement);
  211.             Munger(menuList, offset, nil, sizeof(MenuElement), (Ptr)&element, 0);
  212.             menus->itemsOffset -= 6;
  213.             break;
  214.         }
  215.     }
  216. }
  217.  
  218. static void RemoveMenu(MenuHandle menu)
  219. {
  220.     DeleteMenu((**menu).menuID);
  221. }
  222.  
  223. static void SetMenuTitle(MenuHandle menu, StringPtr title)
  224. {    
  225.     // change the title.
  226.     Munger(menu, offsetof(MenuInfo, menuData), nil, 1 + (**menu).menuData[0], title, 1 + title[0]);
  227. }
  228.  
  229. static void RightJustify(MenusListHandle menuList, MenuHandle menu, StringPtr title, short adjust)
  230. {
  231.     short width = adjust + StrWidth(title);
  232.     // change the width! assume right justification.
  233.     MenusList* menus = *menuList;
  234.     short menuCount = menus->itemsOffset / sizeof(MenuElement);
  235.     MenuElement* element = menus->elements;
  236.     short i;
  237.     
  238.     for (i = 0; i < menuCount; ++i, ++element) {
  239.         if (element->menu == menu) {
  240.             element->leftEdge = (element + 1)->leftEdge - width;
  241.             break;
  242.         }
  243.     }
  244. }
  245.  
  246. //
  247. //    InsertMenuPatch -- Add our menus to the menu list after the system does.
  248. //
  249.  
  250. class InsertMenuPatch : public GenericPatch {
  251. public:
  252.     InsertMenuPatch(void);
  253.     virtual void Behavior(void);
  254. };
  255.  
  256. struct InsertMenuParameters {
  257.     short itsBefore;
  258.     MenuHandle itsMenu;
  259. };
  260.  
  261. typedef struct InsertMenuParameters InsertMenuParameters;
  262.  
  263. typedef pascal void (*InsertMenuProc) (MenuHandle menu, short before);
  264.  
  265. InsertMenuPatch::InsertMenuPatch()
  266. {
  267.     GenericPatch::InitGenericPatch(_InsertMenu, sizeof(InsertMenuParameters));
  268.     Install();
  269. }
  270.  
  271. void InsertMenuPatch::Behavior()
  272. {
  273.     InsertMenuProc oldInsertMenu = (InsertMenuProc)itsOld;
  274.     InsertMenuParameters* params = (InsertMenuParameters*)itsFrame->parameters;
  275.     
  276.     // see if our menus are in the current menu bar.
  277.     if (!IdInMenuList(theMenus, (**theARAStatusMenu).menuID)) {
  278.         // if not, add our menus after the system does.
  279.         (*oldInsertMenu)(theTimeConnectedMenu, 0);
  280.         (*oldInsertMenu)(theARAStatusMenu, 0);
  281. #if __option(a4_globals)
  282.         Disable();
  283.         return;
  284. #endif
  285.     }
  286.  
  287. #if !__option(a4_globals)
  288.     if (params->itsBefore == 0) {
  289.         (*oldInsertMenu) (params->itsMenu, (**theTimeConnectedMenu).menuID);
  290.         AbortTrap();
  291.     }
  292. #endif
  293. }
  294.  
  295. static void DoAbout(StringPtr aboutMessage)
  296. {
  297.     static NMRec notification = { nil, nmType };
  298.     notification.nmStr = aboutMessage;
  299.     notification.nmResp = (ProcPtr)-1;
  300.     NMInstall(¬ification);
  301. }
  302.  
  303. //
  304. //    MenuSelectPatch -- grab menu items after they are selected.
  305. //
  306.  
  307. class MenuSelectPatch : public GenericPatch {
  308. public:
  309.     MenuSelectPatch(void);
  310.     virtual void Behavior(void);
  311. };
  312.  
  313. struct MenuSelectParameters {
  314.     Point itsStartPt;
  315.     long itsResult;
  316. };
  317.  
  318. typedef struct MenuSelectParameters MenuSelectParameters;
  319.  
  320. typedef pascal long (*MenuSelectProcPtr) (Point pt);
  321.  
  322. MenuSelectPatch::MenuSelectPatch()
  323. {
  324.     GenericPatch::InitGenericPatch(_MenuSelect, offsetof(MenuSelectParameters, itsResult));
  325.     Install();
  326. }
  327.  
  328. void MenuSelectPatch::Behavior()
  329. {
  330.     MenuSelectProcPtr oldMenuSelect = (MenuSelectProcPtr)itsOld;
  331.     MenuSelectParameters* params = (MenuSelectParameters*)itsFrame->parameters;
  332.     long result;
  333.     
  334.     DirectRemoveMenu(theMenus, theTimeConnectedMenu);
  335.  
  336. #if !__option(a4_globals)
  337.     { long oldA5 = SetA5((long)itsFrame->ra5);
  338. #endif
  339.     
  340.     params->itsResult = (*oldMenuSelect)(params->itsStartPt);
  341.     
  342. #if !__option(a4_globals)
  343.     SetA5(oldA5); }
  344. #endif
  345.  
  346.     DirectInsertMenu(theMenus, theTimeConnectedMenu, theARAStatusMenu);
  347.  
  348.     EnableItem(theTimeConnectedMenu, 0);
  349.     AbortTrap();
  350.     result = MenuDisable;
  351.     if ((result >> 16) == (**theARAStatusMenu).menuID) {
  352.         short item = result & 0xffff;
  353.         params->itsResult = 0;
  354.         switch (item) {
  355.         case eAboutARAStatus:
  356.             DoAbout(theAboutMessage);
  357.             break;
  358.         case eDisconnect:
  359.             ARADisconnect();
  360.             break;
  361.         case eShowTimeConnected:
  362.             theShowTimeConnected = !theShowTimeConnected;
  363.             CheckItem(theARAStatusMenu, item, theShowTimeConnected);
  364.             if (!theShowTimeConnected) {
  365.                 SetMenuTitle(theTimeConnectedMenu, theEmptyStr);
  366.                 RightJustify(theMenus, theTimeConnectedMenu, theEmptyStr, -4);
  367.                 theMenuBarDirty = true;
  368.                 theLastTimeConnected = 0;
  369.             }
  370.             break;
  371.         }
  372.     }
  373. }
  374.  
  375. //
  376. //    SystemTaskPatch - here we show the time connected periodically.
  377. //
  378.  
  379. class SystemTaskPatch : public GenericPatch {
  380. public:
  381.     SystemTaskPatch(void);
  382.     virtual void Behavior(void);
  383. };
  384.  
  385. SystemTaskPatch::SystemTaskPatch()
  386. {
  387.     GenericPatch::InitGenericPatch(_SystemTask, 0);
  388.     Install();
  389. }
  390.  
  391. extern KeyMap theKeyMap : 0x174;
  392.  
  393. void SystemTaskPatch::Behavior()
  394. {
  395.     TRemoteAccessStatusParam* status = ARAStatus();
  396.     Boolean connected = ((status->statusBits & CctlConnected) != 0);
  397. #if !__option(a4_globals)
  398.     Boolean controlKeyDown = ((theKeyMap[1] & 8) != 0);
  399.     
  400.     if (controlKeyDown)
  401.         status->timeConnected++;
  402.     connected = (connected || controlKeyDown);
  403. #endif
  404.     
  405.     if (connected && theShowTimeConnected) {
  406.         if (status->timeConnected != theLastTimeConnected) {
  407.             char timeBuf[10];
  408.             short hours, minutes, seconds;
  409.         
  410.             theLastTimeConnected = status->timeConnected;
  411.             seconds = theLastTimeConnected;
  412.             minutes = seconds / 60;
  413.             hours = minutes / 60;
  414.             minutes = minutes % 60;
  415.             seconds = seconds % 60;
  416.             sprintf(timeBuf, "%02d:%02d:%02d", hours, minutes, seconds);
  417.             SetMenuTitle(theTimeConnectedMenu, c2pstr(timeBuf));
  418.             RightJustify(theMenus, theTimeConnectedMenu, (StringPtr)timeBuf, 10);
  419.             theMenuBarDirty = true;
  420.         }
  421.     }
  422.     
  423.     // see if we're now connected.
  424.     if (connected != theConnectionState) {
  425.         theConnectionState = connected;
  426.         SetMenuTitle(theARAStatusMenu, (StringPtr)&theIconStrings[connected]);
  427.         if (connected) {
  428.             EnableItem(theARAStatusMenu, eDisconnect);
  429.         } else {
  430.             // clear the time connected value.
  431.             DisableItem(theARAStatusMenu, eDisconnect);
  432.             SetMenuTitle(theTimeConnectedMenu, theEmptyStr);
  433.             RightJustify(theMenus, theTimeConnectedMenu, theEmptyStr, -4);
  434.         }
  435.         theMenuBarDirty = true;
  436.     }
  437.     
  438.     if (theMenuBarDirty) {
  439.         theMenuBarDirty = false;
  440.         DrawMenuBar();
  441.     }
  442. }
  443.  
  444. static void DetachSuite(Handle suiteHandle)
  445. {
  446.     int i;
  447.     IconSuite* suite = *(IconSuite**)suiteHandle;
  448.     
  449.     for (i = 0; i < IconSpace; ++i) {
  450.         Handle icon = suite->table[i];
  451.         if (icon)
  452.             DetachResource(icon);
  453.     }
  454. }
  455.  
  456. static void GetIconString(IconString* iconStr, short id)
  457. {
  458.     OSErr result = GetIconSuite(&iconStr->itsSuite, id, -1L);
  459.     FailNil(iconStr->itsSuite);
  460.     FailErr(result);
  461.     DetachSuite(iconStr->itsSuite);
  462.     iconStr->itsLength = 5;
  463.     iconStr->itsFlag = 1;
  464. }
  465.  
  466. //
  467. //    Install routine. This is where you allocate your patch objects.
  468. //    Throw an exception if something fails.
  469. //
  470.  
  471. void Install()
  472. {
  473.     OSErr result;
  474.     long flags;
  475.     short i;
  476.     
  477.     try {
  478.         // make sure ARA is around.    
  479.         result = Gestalt(gestaltRemoteAccessAttr, &flags);
  480.         FailErr(result);
  481.         FailAssert(flags & (1 << gestaltRemoteAccessExists));
  482.         
  483.         // enough of ARA exists to satisfy us. install patches....
  484.         
  485.         // initialize enough for the menu manager.
  486.         InitFonts();
  487.         
  488.         // allocate our icon suites.
  489.         for (i = 0; i < 3; ++i)
  490.             GetIconString(&theIconStrings[i], 1000 + i);
  491.             
  492.         // get the about string.
  493.         GetIndString(theAboutMessage, cAboutStrings, 1);
  494.  
  495.         // create our system menus.
  496.         theTimeConnectedMenu = NewMenu(cBaseSystemMenuId + 1, theEmptyStr);
  497.         FailNil(theTimeConnectedMenu);
  498.         (**theTimeConnectedMenu).menuWidth = 0;
  499.         
  500.         theARAStatusMenu = NewMenu(cBaseSystemMenuId, theEmptyStr);
  501.         FailNil(theARAStatusMenu);
  502.         AppendMenu(theARAStatusMenu, "\pAbout ARA Status;(Disconnect;Show Time Connected!");
  503.  
  504.         // stuff in the not connected icon.
  505.         SetMenuTitle(theARAStatusMenu, (StringPtr)&theIconStrings[eNotConnectedIcon]);
  506.  
  507.         // patch MenuSelect to check for selections in our menu.
  508.         new MenuSelectPatch;
  509.         
  510.         // patch InsertMenu to add our menus when an app does.
  511.         new InsertMenuPatch;
  512.         
  513.         // patch SystemTask to update time connected display.
  514.         new SystemTaskPatch;
  515.         
  516.         ShowIconFamily(128);
  517.     } catch {
  518.         // extension failed, show sad icon.
  519.         ShowIconFamily(129);
  520.         throw(theException);
  521.     }
  522. }
  523.  
  524. //
  525. //    Remove routine. This is called when system is shutdown, or an exception
  526. //    is thrown.
  527. //
  528.  
  529. void Remove()
  530. {
  531.     Patch::RemoveAll();
  532.     RemoveMenu(theARAStatusMenu);
  533.     DisposeMenu(theARAStatusMenu);
  534.     RemoveMenu(theTimeConnectedMenu);
  535.     DisposeMenu(theTimeConnectedMenu);
  536. }
  537.  
  538. //
  539. // debugging printf.
  540. //
  541.  
  542. static int dprintf(const char* format, ...)
  543. {
  544.     va_list args;
  545.     static char str[256];
  546.     int count;
  547.     
  548.     va_start(args, format);
  549.     count = vsprintf(str, format, args);
  550.     va_end(args);
  551.     DebugStr(c2pstr(str));
  552.         
  553.     return count;
  554. }
  555.